#include "drv_iic.h"
#include "drv_systick.h"
/**************************************
函数名：drv_iic_init
函数功能：对IIC引脚初始化(模拟iic)
输入参数：无
输出参数：无
其它：	//pb6 scl
	   //pb7 sda
****************************************/
void drv_iic_init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;//定义一个GPIO初始化结构体
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//开启GPIOB的时钟
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;//输出
	GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;//开漏输出
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
}

/**************************************
函数名：drv_sda_in
函数功能：将sda数据线设置为输入
输入参数：无
输出参数：无
其它：	//pb6 scl
	   //pb7 sda
****************************************/
void drv_sda_in(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
}

/**************************************
函数名：drv_sda_out
函数功能：将sda数据线设置为输出
输入参数：无
输出参数：无
其它：	//pb6 scl
	   //pb7 sda
****************************************/
void drv_sda_out(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;//定义一个GPIO初始化结构体
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;//输出
	GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;//开漏输出
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
}

/**************************************
函数名：drv_iic_start
函数功能:	IIC起始信号
输入参数：无
输出参数：无
其它：当时钟线为高电平时，数据线由高变为低电平产生一个有效的下降沿
****************************************/
void drv_iic_start(void)
{
	SCL_L;	//拉低时钟线，数据无效，允许数据发生改变
	drv_sda_out();	//SDA配置为输出
	SDA_H;	//拉高数据线
	SCL_H;	//拉高时钟线，使数据有效
	drv_systick_us(5);//延时5us，满足时序要求
	SDA_L;	//拉低数据线，产生下降沿(起始信号)
	drv_systick_us(5);//延时5us，满足时序要求
	SCL_L;	//拉低时钟线，继续通信
}

/**************************************
函数名：drv_sda_out
函数功能：IIC停止信号
输入参数：无
输出参数：无
其它：	当时钟线为高电平时，数据线由低变为高电平产生一个有效的上升沿
****************************************/
void drv_iic_stop(void)
{
	SCL_L;	//拉低时钟线，数据无效，允许数据发生改变
	drv_sda_out();	//SDA配置为输出
	SDA_L;	//拉低数据线
	SCL_H;	//拉高时钟线，使数据有效
	drv_systick_us(5);	//延时5us，满足时序要求
	SDA_H;	//拉高数据线，产生下降沿(终止信号)
	drv_systick_us(5);	//延时5us，满足时序要求
}

/**************************************
函数名：drv_send_ACK
函数功能：发送应答信号
输入参数：无
输出参数：无
其它：	当时钟线为高电平时，数据线产生一个有效的低电平
****************************************/
void drv_send_ACK(void)
{
	SCL_L;	//拉低时钟线，数据无效，允许数据发生改变
	drv_sda_out();	//SDA配置为输出
	SDA_L;	//拉低数据线
	SCL_H;	//拉高时钟线，使数据有效
	drv_systick_us(5);	//延时5us，满足时序要求
	SCL_H;	//拉高时钟线，使数据有效
}

/**************************************
函数名：drv_send_NOACK
函数功能：发送非应答信号
输入参数：无
输出参数：无
其它：	当时钟线为高电平时，数据线产生一个有效的高电平
****************************************/
void drv_send_NOACK(void)
{
	SCL_L;	//拉低时钟线，数据无效，允许数据发生改变
	drv_sda_out();	//SDA配置为输出
	SDA_H;	//拉高数据线
	SCL_H;	//拉高时钟线，使数据有效
	drv_systick_us(5);	//延时5us，满足时序要求
	SCL_L;	//拉低时钟线，继续通信
}

/**************************************
函数名：drv_wait_ACK
函数功能：发送非应答信号
输入参数：无
输出参数：无
其它：	拉高时钟线，去读取数据线上的数据：高电平(非应答)，低电平(应答信号)
****************************************/
uint8_t drv_wait_ACK(void)//等待应答信号
{
	uint16_t time_out=0;
	SCL_L;	//拉低时钟线，使数据无效
	drv_sda_in();//SDA配置为输入
	SCL_H;	//拉高时钟线，使数据有效
	while(SDA_READ)
	{
		time_out++;
		if(time_out>300)//超时
		{
			drv_iic_stop();
			return NOACK;
		}
	}
	SCL_L;
	return ACK;
}

/**************************************
函数名：drv_send_NOACK
函数功能：发送非应答信号
输入参数：无
输出参数：无
其它：	当时钟线为高电平时，数据线上的数据不允许发生改变(稳定不变)
		当时钟线为低电平时，允许数据线上的数据发生改变
****************************************/
void drv_send_data(uint8_t data)//iic发送一个字节数据
{
	uint8_t i=0;
	SCL_L;	//拉低时钟线，是数据无效
	drv_sda_out();	//配置SDA为输出模式
	for(i = 0;i < 8;i++)
	{
		if(data & 0x80)
		{
			SDA_H;//拉高数据线
		}
		else
		{
			SDA_L;//拉低数据线
		}
		SCL_H;
		drv_systick_us(1);
		SCL_L;
		drv_systick_us(1);
		data = data<<1;
	}
}

/**************************************
函数名：drv_read_data
函数功能：iic读取一个字节数据
输入参数：ack_flg:发送ACK的标志
输出参数：无
其它：	当时钟线为高电平时，数据线上的数据不允许发生改变(稳定不变)
		当时钟线为低电平时，允许数据线上的数据发生改变

****************************************/
uint8_t drv_read_data(uint8_t ack_flg)//iic读取一个字节数据
{
	uint8_t read_data=0,i=0;
	SCL_L;				
	drv_sda_in();
	for(i=0;i<8;i++)
	{
		read_data = read_data<<1;
		SCL_H;
		if(SDA_READ)
		{
			read_data = read_data | 0x01;
		}
		drv_systick_us(1);
		SCL_L;
		drv_systick_us(1);
	}
	if(ack_flg == ACK)
	{
		drv_send_ACK();
	}
	else
	{
		drv_send_NOACK();	
	}
	SCL_L;
	return read_data;
}

